前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# 实用工具模块 util

30 秒速记

  • util 是一个工具箱,常用的是 promisify、inspect、format、deprecate、debuglog、types
  • promisify 只适合标准错误优先回调 (err, value) => {},多结果或多次回调的 API 不适用
  • inspect 是给人看的调试输出,不是序列化格式,别拿它的结果去解析
  • debuglog('foo') 只有 NODE_DEBUG=foo 时才输出,适合留在库代码里的调试日志
  • util.isArray 这类老判断函数已废弃,改用 Array.isArray 和 util.types

util 是 Node.js 自带的工具箱,没有统一主题,记住几个高频的就够用。 用得最多的是 promisify,把 fs.readFile 这类错误优先回调的 API 转成返回 Promise 的函数;inspect 是 console.log 打对象时背后用的格式化,调深层对象很方便;debuglog 能写只在设置 NODE_DEBUG 环境变量时才输出的日志;deprecate 给要下线的函数加废弃提示。现在 fs/promises、timers/promises 都有现成的 Promise 版本,promisify 主要用在老的第三方回调库上。

理解「实用工具模块 util」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 module 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

util 里几个高频 API 的最小用法:

const util = require('util');
const fs = require('fs');

// 1. promisify:错误优先回调 → Promise
const readFile = util.promisify(fs.readFile);
readFile(__filename, 'utf8').then((s) => console.log(s.length));

// 2. callbackify:反过来,Promise → 错误优先回调
const legacy = util.callbackify(async (x) => x * 2);
legacy(21, (err, v) => console.log(v)); // 42

// 3. format:printf 风格拼字符串,console.log 内部就用它
console.log(util.format('%s 有 %d 道题', '前端', 300)); // 前端 有 300 道题

// 4. inspect:调试输出,控制展开深度
const deep = { a: { b: { c: { d: 1 } } } };
console.log(util.inspect(deep));                  // { a: { b: { c: [Object] } } }
console.log(util.inspect(deep, { depth: null })); // { a: { b: { c: { d: 1 } } } }

// 5. deprecate:首次调用时打印一次废弃警告
const oldApi = util.deprecate(() => 'ok', 'oldApi() 已废弃,请改用 newApi()', 'DEP_MY_001');
oldApi(); // 打印 DeprecationWarning,返回 'ok'

// 6. isDeepStrictEqual:深比较
console.log(util.isDeepStrictEqual({ a: [1] }, { a: [1] })); // true
@前端进阶之旅: 代码已经复制到剪贴板

debuglog 要配合环境变量看效果:

const debug = util.debuglog('app');
debug('连接数 %d', 3); // 只有 NODE_DEBUG=app node index.js 时才输出
@前端进阶之旅: 代码已经复制到剪贴板

较新的版本里还有 util.parseArgs(Node.js 18.3+)解析命令行参数,适合写小工具脚本,不用装 yargs;以及 util.styleText 给终端输出加颜色。早年的 util.isArray、util.isString 等类型判断函数已经废弃,分别用 Array.isArray、typeof 和 util.types 代替。

面试官追问

追问 1util.promisify 能转所有回调风格的函数吗?
参考回答

不能。它要求最后一个参数是 (err, value) 形式的回调、而且只调一次。回调有多个结果值、或者会被多次调用(其实是事件),转出来的结果都不对,这种要手写 new Promise 包装。

追问 2promisify(setTimeout) 能用吗?
参考回答

能,setTimeout 带了 util.promisify.custom 自定义实现,await promisify(setTimeout)(100) 就是等 100ms。不过现在直接 require('timers/promises').setTimeout 更直观。

追问 3console.log 一个嵌套很深的对象,里面显示 [Object],怎么看全?
参考回答

默认只展开 2 层。用 console.log(util.inspect(obj, { depth: null })) 展开全部,或者 console.dir(obj, { depth: null })。循环引用它会标成 [Circular *1],不会死循环。

追问 4库里想留调试日志,又不想污染使用者的控制台,怎么做?
参考回答

const debug = util.debuglog('mylib'),平时 debug('...') 不输出,用户需要时 NODE_DEBUG=mylib node app.js 才打印。不用额外装 debug 包。

追问 5判断一个值是不是 Promise 或者 Date,用 instanceof 有什么问题?
参考回答

跨 vm 上下文或跨 realm 创建的对象,instanceof 会判断失败。util.types.isPromise(v)、util.types.isDate(v) 是按内部类型判断的,更可靠。

# debuglog(section)

30 秒速记

  • util.debuglog('foo') 返回一个日志函数,平时静默,启动时带 NODE_DEBUG=foo 才打印
  • 多个分区用逗号:NODE_DEBUG=first,second;Node 10+ 支持通配符 NODE_DEBUG=foo*
  • 输出格式 FOO 6347: hello:分区名大写 + 进程 pid + 消息
  • logger.enabled(Node 14.9+)可以判断开没开,拼大对象前先判断,省掉白算
  • 只适合临时排障,审计、业务日志别放这里,没开开关就等于没写

util.debuglog 就是一个带开关的 console.log,开关是环境变量 NODE_DEBUG。 代码里写 const log = util.debuglog('foo'),平时跑 node app.js 什么都不打,出问题时用 NODE_DEBUG=foo node app.js 启动,日志就出来了,格式是 FOO 6347: hello,中间那个数字是进程 pid。好处是调试代码可以一直留在仓库里,不用上线前删。Node 自己的核心模块也是这么埋点的,比如 NODE_DEBUG=http,net 能直接看到 http 模块内部的连接日志,排查连接复用问题很好用。

很有用的调试方法。可以通过 util.debuglog(name) 来创建一个调试fn,这个fn的特点是,只有在运行程序时候,声明环境变量NODE_DEBUG=name,才会打印出调试信息。

可以看下面的例子,直接运行 node debuglog.js,没有任何输出。需要NODE_DEBUG=foo,才会有打印信息.

var util = require('util');
var logger = util.debuglog('foo');

logger('hello');
@前端进阶之旅: 代码已经复制到剪贴板

如下所示,注意,6347 是当前进程id。

➜  2016.12.02-util git:(master) ✗ NODE_DEBUG=foo node debuglog.js
FOO 6347: hello world
@前端进阶之旅: 代码已经复制到剪贴板

此外,还可以一次指定多个name,通过逗号分隔。

var util = require('util');
var firstLogger = util.debuglog('first');
var secondLogger = util.debuglog('second');
var thirdLogger = util.debuglog('third');

firstLogger('hello');
secondLogger('hello');
thirdLogger('hello');
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
      • debuglog(section)
      • 将方法标识为作废:util.deprecate(fn, str)
      • 格式化打印:util.format(format[, …args])
      • 调试方法:util.inspect(obj[, options])
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

实用工具模块 util|Nodejs专题系列

# 实用工具模块 util

30 秒速记

  • util 是一个工具箱,常用的是 promisify、inspect、format、deprecate、debuglog、types
  • promisify 只适合标准错误优先回调 (err, value) => {},多结果或多次回调的 API 不适用
  • inspect 是给人看的调试输出,不是序列化格式,别拿它的结果去解析
  • debuglog('foo') 只有 NODE_DEBUG=foo 时才输出,适合留在库代码里的调试日志
  • util.isArray 这类老判断函数已废弃,改用 Array.isArray 和 util.types

util 是 Node.js 自带的工具箱,没有统一主题,记住几个高频的就够用。 用得最多的是 promisify,把 fs.readFile 这类错误优先回调的 API 转成返回 Promise 的函数;inspect 是 console.log 打对象时背后用的格式化,调深层对象很方便;debuglog 能写只在设置 NODE_DEBUG 环境变量时才输出的日志;deprecate 给要下线的函数加废弃提示。现在 fs/promises、timers/promises 都有现成的 Promise 版本,promisify 主要用在老的第三方回调库上。

理解「实用工具模块 util」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 module 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

util 里几个高频 API 的最小用法:

const util = require('util');
const fs = require('fs');

// 1. promisify:错误优先回调 → Promise
const readFile = util.promisify(fs.readFile);
readFile(__filename, 'utf8').then((s) => console.log(s.length));

// 2. callbackify:反过来,Promise → 错误优先回调
const legacy = util.callbackify(async (x) => x * 2);
legacy(21, (err, v) => console.log(v)); // 42

// 3. format:printf 风格拼字符串,console.log 内部就用它
console.log(util.format('%s 有 %d 道题', '前端', 300)); // 前端 有 300 道题

// 4. inspect:调试输出,控制展开深度
const deep = { a: { b: { c: { d: 1 } } } };
console.log(util.inspect(deep));                  // { a: { b: { c: [Object] } } }
console.log(util.inspect(deep, { depth: null })); // { a: { b: { c: { d: 1 } } } }

// 5. deprecate:首次调用时打印一次废弃警告
const oldApi = util.deprecate(() => 'ok', 'oldApi() 已废弃,请改用 newApi()', 'DEP_MY_001');
oldApi(); // 打印 DeprecationWarning,返回 'ok'

// 6. isDeepStrictEqual:深比较
console.log(util.isDeepStrictEqual({ a: [1] }, { a: [1] })); // true
@前端进阶之旅: 代码已经复制到剪贴板

debuglog 要配合环境变量看效果:

const debug = util.debuglog('app');
debug('连接数 %d', 3); // 只有 NODE_DEBUG=app node index.js 时才输出
@前端进阶之旅: 代码已经复制到剪贴板

较新的版本里还有 util.parseArgs(Node.js 18.3+)解析命令行参数,适合写小工具脚本,不用装 yargs;以及 util.styleText 给终端输出加颜色。早年的 util.isArray、util.isString 等类型判断函数已经废弃,分别用 Array.isArray、typeof 和 util.types 代替。

面试官追问

追问 1util.promisify 能转所有回调风格的函数吗?
参考回答

不能。它要求最后一个参数是 (err, value) 形式的回调、而且只调一次。回调有多个结果值、或者会被多次调用(其实是事件),转出来的结果都不对,这种要手写 new Promise 包装。

追问 2promisify(setTimeout) 能用吗?
参考回答

能,setTimeout 带了 util.promisify.custom 自定义实现,await promisify(setTimeout)(100) 就是等 100ms。不过现在直接 require('timers/promises').setTimeout 更直观。

追问 3console.log 一个嵌套很深的对象,里面显示 [Object],怎么看全?
参考回答

默认只展开 2 层。用 console.log(util.inspect(obj, { depth: null })) 展开全部,或者 console.dir(obj, { depth: null })。循环引用它会标成 [Circular *1],不会死循环。

追问 4库里想留调试日志,又不想污染使用者的控制台,怎么做?
参考回答

const debug = util.debuglog('mylib'),平时 debug('...') 不输出,用户需要时 NODE_DEBUG=mylib node app.js 才打印。不用额外装 debug 包。

追问 5判断一个值是不是 Promise 或者 Date,用 instanceof 有什么问题?
参考回答

跨 vm 上下文或跨 realm 创建的对象,instanceof 会判断失败。util.types.isPromise(v)、util.types.isDate(v) 是按内部类型判断的,更可靠。

# debuglog(section)

30 秒速记

  • util.debuglog('foo') 返回一个日志函数,平时静默,启动时带 NODE_DEBUG=foo 才打印
  • 多个分区用逗号:NODE_DEBUG=first,second;Node 10+ 支持通配符 NODE_DEBUG=foo*
  • 输出格式 FOO 6347: hello:分区名大写 + 进程 pid + 消息
  • logger.enabled(Node 14.9+)可以判断开没开,拼大对象前先判断,省掉白算
  • 只适合临时排障,审计、业务日志别放这里,没开开关就等于没写

util.debuglog 就是一个带开关的 console.log,开关是环境变量 NODE_DEBUG。 代码里写 const log = util.debuglog('foo'),平时跑 node app.js 什么都不打,出问题时用 NODE_DEBUG=foo node app.js 启动,日志就出来了,格式是 FOO 6347: hello,中间那个数字是进程 pid。好处是调试代码可以一直留在仓库里,不用上线前删。Node 自己的核心模块也是这么埋点的,比如 NODE_DEBUG=http,net 能直接看到 http 模块内部的连接日志,排查连接复用问题很好用。

很有用的调试方法。可以通过 util.debuglog(name) 来创建一个调试fn,这个fn的特点是,只有在运行程序时候,声明环境变量NODE_DEBUG=name,才会打印出调试信息。

可以看下面的例子,直接运行 node debuglog.js,没有任何输出。需要NODE_DEBUG=foo,才会有打印信息.

var util = require('util');
var logger = util.debuglog('foo');

logger('hello');
@前端进阶之旅: 代码已经复制到剪贴板

如下所示,注意,6347 是当前进程id。

➜  2016.12.02-util git:(master) ✗ NODE_DEBUG=foo node debuglog.js
FOO 6347: hello world
@前端进阶之旅: 代码已经复制到剪贴板

此外,还可以一次指定多个name,通过逗号分隔。

var util = require('util');
var firstLogger = util.debuglog('first');
var secondLogger = util.debuglog('second');
var thirdLogger = util.debuglog('third');

firstLogger('hello');
secondLogger('hello');
thirdLogger('hello');
@前端进阶之旅: 代码已经复制到剪贴板

运行如下:

FOO 6347: hello world
➜  2016.12.02-util git:(master) ✗ NODE_DEBUG=first,second node debuglog.js
FIRST 6456: hello
SECOND 6456: hello
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1跑了 node app.js 一行调试日志都没有,是不是 logger 没执行到?
参考回答

不一定,debuglog 默认就是静默的。用 NODE_DEBUG=foo node app.js 再跑一次,有输出说明代码路径是通的,之前只是没开开关。

追问 2我只想看 first 和 second 两个分区,third 不要,怎么启动?
参考回答

NODE_DEBUG=first,second node app.js。分区名大小写不敏感,Node 10 以后还能写 NODE_DEBUG=first* 一次开一组前缀相同的分区。

追问 3开了 cluster,终端里一堆 FOO 6347:、FOO 6350: 混在一起,怎么分?
参考回答

中间那个数字就是 pid,先按它分组能分出是哪个 worker。但同一个进程里并发请求照样交错,真要串起一次请求,得在消息里自己带上 requestId。

追问 4日志里要打一个很大的对象,没开调试的时候会不会白白序列化?
参考回答

会。参数在调用前就求值了,log('%o', bigObj) 里的 bigObj 本身不贵,但如果你写成 log(JSON.stringify(bigObj)) 就是每次都算。用 if (log.enabled) log(JSON.stringify(bigObj)) 包一下,enabled 是 Node 14.9 加的。

追问 5团队想把所有业务日志都换成 util.debuglog,你同意吗?
参考回答

不同意。它的定位是「出问题临时打开」,生产上默认是关的,审计和关键业务事件要走 pino、winston 这类常开的日志通道,debuglog 只放排障细节。

# 将方法标识为作废:util.deprecate(fn, str)

← 9.1 事件机制 events9.3 数据加密 crypto →

fe